/*
 * Copyright (C) 2012 genzo
 */
package jp.gr.java_conf.genzo.wolrepeater;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

/**
 *
 * データ管理クラス.
 *
 */
public class Model implements Iterable<MachineInfo> {
    /** ファイル名. */
    private static final String FILE = "data.json";

    /** 型情報. */
    private static final Type TYPE = (new TypeToken<List<MachineInfo>>() {
    }).getType();

    /** 登録情報. */
    private List<MachineInfo> mItems = new ArrayList<MachineInfo>();

    /** PropertyChangeSupport. */
    private final PropertyChangeSupport mPropertyChangeSupport = new PropertyChangeSupport(
            this);

    /**
     * PropertyChangeSupport 追加.
     *
     * @param listener
     *            PropertyChangeSupport
     */
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        mPropertyChangeSupport.addPropertyChangeListener(listener);
    }

    /**
     * PropertyChangeSupport 削除.
     *
     * @param listener
     *            PropertyChangeSupport
     */
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        mPropertyChangeSupport.removePropertyChangeListener(listener);
    }

    /**
     * イベント通知.
     *
     * @param mode
     *            モード
     * @param oldValue
     *            旧値
     * @param newValue
     *            現値
     */
    private void firePropertyChange(String mode, Object oldValue,
            Object newValue) {
        mPropertyChangeSupport.firePropertyChange(mode, oldValue, newValue);
    }

    /**
     * イベント通知（強制）.
     */
    public void firePropertyChange() {
        mPropertyChangeSupport.firePropertyChange("state_change", null, null);
    }

    /**
     * ロード.
     *
     * データを読み込みモデルを構築する.
     */
    public void load() {

        try {
            File file = WolRepeaterApp.getApp().getFileStreamPath(FILE);
            Gson gson = new Gson();
            mItems = gson.fromJson(new FileReader(file), TYPE);
        } catch (IOException e) {
            // IO系はスルー
            L.e("Model load error", e);
        }
    }

    /**
     * イテレータ取得.
     * 
     * @return イテレータ
     */
    @Override
    public Iterator<MachineInfo> iterator() {
        return get().iterator();
    }

    /**
     * データ取得.
     *
     * @return 内部データのコピー
     */
    public List<MachineInfo> get() {
        return new ArrayList<MachineInfo>(mItems);
    }

    /**
     * デー取得.
     *
     * 指定インデックス番目のデータを返却する.
     *
     * @param index
     *            インデックス
     * @return 行データ
     */
    public MachineInfo get(int index) {
        return mItems.get(index);
    }

    /**
     * 削除.
     *
     * 指定インデックス番目のデータを削除する.
     *
     * @param index
     *            インデックス
     */
    public void remove(int index) {
        MachineInfo old = get(index);
        mItems.remove(index);
        save();
        firePropertyChange("remove", old, null);
    }

    /**
     * 追加.
     *
     * データを追加する。
     *
     * @param item
     *            設定情報
     */
    public void add(MachineInfo item) {
        mItems.add(item);
        save();
        firePropertyChange("add", null, item);
    }

    /**
     * 更新.
     *
     * 指定インデックス番目の情報を更新する.
     *
     * @param index
     *            インデックス
     * @param item
     *            設定情報
     */
    public synchronized void update(int index, MachineInfo item) {
        MachineInfo old = get(index);
        mItems.add(index, item);
        mItems.remove(index + 1);
        save();
        firePropertyChange("update", old, item);
    }

    /**
     * データ保存.
     *
     * ファイルにデータを保存する。
     */
    public void save() {
        Writer writer = null;
        try {
            writer = new FileWriter(WolRepeaterApp.getApp().getFileStreamPath(
                    FILE));
            Gson gson = new Gson();
            writer.write(gson.toJson(mItems, TYPE));

            writer.flush();
        } catch (IOException e) {
            // ここは見逃し
            L.e("Model save error", e);
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (Exception e) {
                    L.e("file close error!!", e);
                }
            }
        }
    }
}
